#ifndef FORMULAGENERATOR_H
#define FORMULAGENERATOR_H

#include <map>
#include <string>
#include <vector>
#include "tableconstraint.h"
#include "primarykeyconstraint.h"
#include "foreignkeyconstraint.h"
#include "checkconstraint.h"
#include "booleanExpression.h"
#include "logicBinaryOperation.h"
#include "expression.h"
using namespace std;

// forward declarations.
class Schema;
class SchemaComponentFormula;
class SchemaComponent;
class Table;
class TableConstraint;
class View;
class QueryTree;
class SimpleQuery;
class Formula;
class FromComponent;
//class Expression;
class Substitution;


/*
    Class: FormulaGenerator.
    Class that generates formulas of a SchemaComponent. Implemented as a Visitor pattern.
*/
class FormulaGenerator
{
    /* Section: public */
    public:
        FormulaGenerator(Schema * schema = NULL);

        virtual ~FormulaGenerator();

        void setSchema(Schema * schema);

        bool generateFormulaFor(const string & name, SchemaComponentFormula * & formula);


    /* Section: private */
    private:
        /*
            Variable: generated.
            Type: map<string,SchemaComponentFormula>
            Maps a SchemaComponent to its SchemaComponentFormula.
        */
        map<string,SchemaComponentFormula *> * generated;

        /*
            Variable:  schema
            Type: Schema *
            Schema of the data base we wants Test Case.
        */
        Schema * schema;

        void generate(const string & component_name);

        SchemaComponentFormula * generate(SchemaComponent * schema_component);

        SchemaComponentFormula * generate(Table * table);

        SchemaComponentFormula * generate(View * view);

        BooleanExpression * generate(TableConstraint * constraint, Table * table);

	BooleanExpression * generate(CheckConstraint * constraint, Table * table);

        BooleanExpression * generate(PrimaryKeyConstraint * constraint, Table * table);

        BooleanExpression * generate(ForeignKeyConstraint * constraint, Table * table);


        SchemaComponentFormula * generate(QueryTree * query_tree, vector<Substitution *> * upper_substitutions, vector<FromComponent *> * upper_from_components);

        SchemaComponentFormula * generate(SimpleQuery * query, vector<Substitution *> * upper_substitutions, vector<FromComponent *> * upper_from_components);

        void generateFromFormulas(vector<FromComponent *> * from_components);

        vector<Formula *> * calculateCartesianProduct(vector<FromComponent *> * from_components);

        Expression * replaceColumnReferenceByExpression(Expression * expression, vector<Substitution *> * substitutions, vector<Substitution *> * upper_substitutions, vector<FromComponent *> * from_components,vector<FromComponent *> * upper_from_components);

        Expression * resolveExists(Expression * expression, vector<Substitution *> * upper_substitutions,vector<FromComponent *> * upper_components);

        Expression * createDisjunction(vector<Formula *> * formulas);

        Expression * createConjunction(vector<Formula *> * formulas);

        void updateSubstitutionsWithRename(Formula * formula, const string & rename);

        vector<Substitution *> * mergeSubstitutions(vector<Substitution *> * s1, vector<Substitution *> * s2);

        vector<Formula *> * generateWhereFormula(Expression * where_expression,vector<Formula *> * cartesian_product,vector<Substitution *> * upper_substitutions,vector<FromComponent *> * from_components, vector<FromComponent *> * upper_from_components);

        Expression * searchSubstitution(const string & to_search, vector<Substitution *> * substitutions, vector<Substitution *> * upper_substitutions);

        string searchForTable(const string & column, vector<FromComponent *> * from_components, vector<FromComponent *> * upper_from_components);

        void computeQuerySubstitutions(vector<Formula *> * formulas, vector<Expression *> * select_expressions, vector<Substitution *> * upper_substitutions, vector<FromComponent *> * from_components, vector<FromComponent *> * upper_from_components);
};

#endif // FORMULAGENERATOR_H
